Towards new device-interface setup code for the frontend drivers.
Added a synchronous send-and-get-response call to the control
interface API. Modified and extended the domain-controller messaging
protocol.
return IRQ_HANDLED;
}
-int ctrl_if_send_message_noblock(
+int
+ctrl_if_send_message_noblock(
ctrl_msg_t *msg,
ctrl_msg_handler_t hnd,
unsigned long id)
return 0;
}
-int ctrl_if_send_message_block(
+int
+ctrl_if_send_message_block(
ctrl_msg_t *msg,
ctrl_msg_handler_t hnd,
unsigned long id,
return rc;
}
-int ctrl_if_enqueue_space_callback(struct tq_struct *task)
+/* Allow a reponse-callback handler to find context of a blocked requester. */
+struct rsp_wait {
+ ctrl_msg_t *msg; /* Buffer for the response message. */
+ struct task_struct *task; /* The task that is blocked on the response. */
+ int done; /* Indicate to 'task' that response is rcv'ed. */
+};
+
+static void __ctrl_if_get_response(ctrl_msg_t *msg, unsigned long id)
+{
+ struct rsp_wait *wait = (struct rsp_wait *)id;
+ struct task_struct *task = wait->task;
+
+ memcpy(wait->msg, msg, sizeof(*msg));
+ wmb();
+ wait->done = 1;
+
+ wake_up_process(task);
+}
+
+int
+ctrl_if_send_message_and_get_response(
+ ctrl_msg_t *msg,
+ ctrl_msg_t *rmsg,
+ long wait_state)
+{
+ struct rsp_wait wait;
+ int rc;
+
+ wait.msg = rmsg;
+ wait.done = 0;
+ wait.task = current;
+
+ if ( (rc = ctrl_if_send_message_block(msg, __ctrl_if_get_response,
+ (unsigned long)&wait,
+ wait_state)) != 0 )
+ return rc;
+
+ for ( ; ; )
+ {
+ /* NB. Can't easily support TASK_INTERRUPTIBLE here. */
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ if ( wait.done )
+ break;
+ schedule();
+ }
+
+ set_current_state(TASK_RUNNING);
+ return 0;
+}
+
+int
+ctrl_if_enqueue_space_callback(
+ struct tq_struct *task)
{
control_if_t *ctrl_if = get_ctrl_if();
return TX_FULL(ctrl_if);
}
-void ctrl_if_send_response(ctrl_msg_t *msg)
+void
+ctrl_if_send_response(
+ ctrl_msg_t *msg)
{
control_if_t *ctrl_if = get_ctrl_if();
unsigned long flags;
ctrl_if_notify_controller();
}
-int ctrl_if_register_receiver(
+int
+ctrl_if_register_receiver(
u8 type,
ctrl_msg_handler_t hnd,
unsigned int flags)
return !inuse;
}
-void ctrl_if_unregister_receiver(u8 type, ctrl_msg_handler_t hnd)
+void
+ctrl_if_unregister_receiver(
+ u8 type,
+ ctrl_msg_handler_t hnd)
{
unsigned long flags;
int err = 0;
int i;
- DPRINTK("> nr_interfaces=%d\n", status->nr_interfaces);
+ DPRINTK("> max_handle=%d\n", status->max_handle);
- netctrl.interface_n = status->nr_interfaces;
+ /* XXX FIXME: Abuse of 'max_handle' as interface count. */
+ netctrl.interface_n = status->max_handle;
netctrl.connected_n = 0;
for ( i = 0; i < netctrl.interface_n; i++ )
cmsg.subtype = CMSG_NETIF_FE_DRIVER_STATUS_CHANGED;
cmsg.length = sizeof(netif_fe_driver_status_changed_t);
st.status = NETIF_DRIVER_STATUS_UP;
- st.nr_interfaces = 0;
+ st.max_handle = 0;
memcpy(cmsg.msg, &st, sizeof(st));
ctrl_if_send_message_block(&cmsg, NULL, 0, TASK_UNINTERRUPTIBLE);
cmsg.subtype = CMSG_NETIF_FE_DRIVER_STATUS_CHANGED;
cmsg.length = sizeof(netif_fe_driver_status_changed_t);
st.status = NETIF_DRIVER_STATUS_UP;
- st.nr_interfaces = 0;
+ st.max_handle = 0;
memcpy(cmsg.msg, &st, sizeof(st));
ctrl_if_send_message_block(&cmsg, NULL, 0, TASK_UNINTERRUPTIBLE);
#endif
* function returns.
* 2. If @hnd is NULL then no callback is executed.
*/
-int ctrl_if_send_message_noblock(
+int
+ctrl_if_send_message_noblock(
ctrl_msg_t *msg,
ctrl_msg_handler_t hnd,
unsigned long id);
* function returns.
* 2. If @hnd is NULL then no callback is executed.
*/
-int ctrl_if_send_message_block(
+int
+ctrl_if_send_message_block(
ctrl_msg_t *msg,
ctrl_msg_handler_t hnd,
unsigned long id,
long wait_state);
+/*
+ * Send @msg to the domain controller. Block until the response is received,
+ * and then copy it into the provided buffer, @rmsg.
+ */
+int
+ctrl_if_send_message_and_get_response(
+ ctrl_msg_t *msg,
+ ctrl_msg_t *rmsg,
+ long wait_state);
+
/*
* Request a callback when there is /possibly/ space to immediately send a
* message to the domain controller. This function returns 0 if there is
* still be executed. If this function returns 1 then the callback /will/ be
* executed when space becomes available.
*/
-int ctrl_if_enqueue_space_callback(struct tq_struct *task);
+int
+ctrl_if_enqueue_space_callback(
+ struct tq_struct *task);
/*
* Send a response (@msg) to a message from the domain controller. This will
* 1. The @msg is copied and so can be freed after this function returns.
* 2. The @msg may be the original request message, modified in-place.
*/
-void ctrl_if_send_response(ctrl_msg_t *msg);
+void
+ctrl_if_send_response(
+ ctrl_msg_t *msg);
/*
* Register a receiver for typed messages from the domain controller. The
* Unregister a receiver for typed messages from the domain controller. The
* handler (@hnd) will not be executed after this function returns.
*/
-void ctrl_if_unregister_receiver(u8 type, ctrl_msg_handler_t hnd);
+void
+ctrl_if_unregister_receiver(
+ u8 type, ctrl_msg_handler_t hnd);
/* Suspend/resume notifications. */
void ctrl_if_suspend(void);
switch ( TYPE(xum->msg.type, xum->msg.subtype) )
{
case TYPE(CMSG_BLKIF_FE, CMSG_BLKIF_FE_DRIVER_STATUS_CHANGED):
- P2C(blkif_fe_driver_status_changed_t, nr_interfaces, u32);
+ P2C(blkif_fe_driver_status_changed_t, max_handle, u32);
break;
case TYPE(CMSG_NETIF_FE, CMSG_NETIF_FE_DRIVER_STATUS_CHANGED):
- P2C(netif_fe_driver_status_changed_t, nr_interfaces, u32);
+ P2C(netif_fe_driver_status_changed_t, max_handle, u32);
break;
}
return dict;
case TYPE(CMSG_NETIF_FE, CMSG_NETIF_FE_DRIVER_STATUS_CHANGED):
C2P(netif_fe_driver_status_changed_t, status, Int, Long);
- C2P(netif_fe_driver_status_changed_t, nr_interfaces, Int, Long);
+ C2P(netif_fe_driver_status_changed_t, max_handle, Int, Long);
return dict;
case TYPE(CMSG_NETIF_FE, CMSG_NETIF_FE_INTERFACE_CONNECT):
C2P(netif_fe_interface_connect_t, handle, Int, Long);
break;
case TYPE(CMSG_NETIF_FE, CMSG_NETIF_FE_DRIVER_STATUS_CHANGED):
P2C(netif_fe_driver_status_changed_t, status, u32);
- P2C(netif_fe_driver_status_changed_t, nr_interfaces, u32);
+ P2C(netif_fe_driver_status_changed_t, max_handle, u32);
break;
}
def recv_fe_driver_status_changed(self, msg, req):
if not req: return
msg = packMsg('netif_fe_driver_status_changed_t',
- { 'status' : NETIF_DRIVER_STATUS_UP,
- 'nr_interfaces' : len(self.devices) })
+ { 'status' : NETIF_DRIVER_STATUS_UP,
+ ## FIXME: max_handle should be max active interface id
+ 'max_handle' : len(self.devices) })
self.writeRequest(msg)
for dev in self.devices.values():
dev.attach_fe_device()
#define CMSG_BLKIF_FE_DRIVER_STATUS_CHANGED 32
#define CMSG_BLKIF_FE_INTERFACE_CONNECT 33
#define CMSG_BLKIF_FE_INTERFACE_DISCONNECT 34
+#define CMSG_BLKIF_FE_INTERFACE_QUERY 35
/* These are used by both front-end and back-end drivers. */
#define blkif_vdev_t u16
* Notify a guest about a status change on one of its block interfaces.
* If the interface is DESTROYED or DOWN then the interface is disconnected:
* 1. The shared-memory frame is available for reuse.
- * 2. Any unacknowledged messgaes pending on the interface were dropped.
+ * 2. Any unacknowledged messages pending on the interface were dropped.
*/
#define BLKIF_INTERFACE_STATUS_DESTROYED 0 /* Interface doesn't exist. */
#define BLKIF_INTERFACE_STATUS_DISCONNECTED 1 /* Exists but is disconnected. */
* CMSG_BLKIF_FE_DRIVER_STATUS_CHANGED:
* Notify the domain controller that the front-end driver is DOWN or UP.
* When the driver goes DOWN then the controller will send no more
- * status-change notifications. When the driver comes UP then the controller
- * will send a notification for each interface that currently exists.
+ * status-change notifications.
* If the driver goes DOWN while interfaces are still UP, the domain
* will automatically take the interfaces DOWN.
+ *
+ * NB. The controller should not send an INTERFACE_STATUS_CHANGED message
+ * for interfaces that are active when it receives an UP notification. We
+ * expect that the frontend driver will query those interfaces itself.
*/
#define BLKIF_DRIVER_STATUS_DOWN 0
#define BLKIF_DRIVER_STATUS_UP 1
/* IN */
u32 status; /* 0: BLKIF_DRIVER_STATUS_??? */
/* OUT */
- /*
- * Tells driver how many interfaces it should expect to immediately
- * receive notifications about.
- */
- u32 nr_interfaces; /* 4 */
+ /* Driver should query interfaces [0..max_handle]. */
+ u32 max_handle; /* 4 */
} PACKED blkif_fe_driver_status_changed_t; /* 8 bytes */
/*
u32 handle; /* 0 */
} PACKED blkif_fe_interface_disconnect_t; /* 4 bytes */
+/*
+ * CMSG_BLKIF_FE_INTERFACE_QUERY:
+ */
+typedef struct {
+ /* IN */
+ u32 handle; /* 0 */
+ /* OUT */
+ u32 status; /* 4 */
+ u16 evtchn; /* 8: (only if status == BLKIF_INTERFACE_STATUS_CONNECTED). */
+ domid_t domid; /* 10: status != BLKIF_INTERFACE_STATUS_DESTROYED */
+} PACKED blkif_fe_interface_query_t; /* 12 bytes */
+
/******************************************************************************
* BLOCK-INTERFACE BACKEND DEFINITIONS
#define CMSG_NETIF_FE_DRIVER_STATUS_CHANGED 32
#define CMSG_NETIF_FE_INTERFACE_CONNECT 33
#define CMSG_NETIF_FE_INTERFACE_DISCONNECT 34
+#define CMSG_NETIF_FE_INTERFACE_QUERY 35
/*
* CMSG_NETIF_FE_INTERFACE_STATUS_CHANGED:
* CMSG_NETIF_FE_DRIVER_STATUS_CHANGED:
* Notify the domain controller that the front-end driver is DOWN or UP.
* When the driver goes DOWN then the controller will send no more
- * status-change notifications. When the driver comes UP then the controller
- * will send a notification for each interface that currently exists.
+ * status-change notifications.
* If the driver goes DOWN while interfaces are still UP, the domain
* will automatically take the interfaces DOWN.
+ *
+ * NB. The controller should not send an INTERFACE_STATUS_CHANGED message
+ * for interfaces that are active when it receives an UP notification. We
+ * expect that the frontend driver will query those interfaces itself.
*/
#define NETIF_DRIVER_STATUS_DOWN 0
#define NETIF_DRIVER_STATUS_UP 1
/* IN */
u32 status; /* 0: NETIF_DRIVER_STATUS_??? */
/* OUT */
- /*
- * Tells driver how many interfaces it should expect to immediately
- * receive notifications about.
- */
- u32 nr_interfaces; /* 4 */
+ /* Driver should query interfaces [0..max_handle]. */
+ u32 max_handle; /* 4 */
} PACKED netif_fe_driver_status_changed_t; /* 8 bytes */
/*
u32 handle; /* 0 */
} PACKED netif_fe_interface_disconnect_t; /* 4 bytes */
+/*
+ * CMSG_NETIF_FE_INTERFACE_QUERY:
+ */
+typedef struct {
+ /* IN */
+ u32 handle; /* 0 */
+ /* OUT */
+ u32 status; /* 4 */
+ u16 evtchn; /* 8: status == NETIF_INTERFACE_STATUS_CONNECTED */
+ u8 mac[6]; /* 10: status == NETIF_INTERFACE_STATUS_CONNECTED */
+ domid_t domid; /* 16: status != NETIF_INTERFACE_STATUS_DESTROYED */
+} PACKED netif_fe_interface_query_t; /* 18 bytes */
+
/******************************************************************************
* NETWORK-INTERFACE BACKEND DEFINITIONS